<!DOCTYPE html>


<html lang="zh-CN">


<head>
  <meta charset="utf-8" />
  <meta name="baidu-site-verification" content="code-kg5UjKJZM2" />
   
  <meta name="keywords" content="活,炼" />
   
  <meta name="description" content="shimmerjordan" />
  
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
  <title>
    Deploy Github Actions |  丛烨-shimmerjordan
  </title>
  <meta name="generator" content="hexo-theme-ayer">
  
  <link rel="shortcut icon" href="/favicon.ico" />
  
  
<link rel="stylesheet" href="/dist/main.css">

  <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/Shen-Yu/cdn/css/remixicon.min.css">
  
<link rel="stylesheet" href="/css/custom.css">

  
  <script src="https://cdn.jsdelivr.net/npm/pace-js@1.0.2/pace.min.js"></script>
  
  

<script type="text/javascript">
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');

ga('create', 'G-Q0DT8B8VJW', 'auto');
ga('send', 'pageview');

</script>



  
<script>
var _hmt = _hmt || [];
(function() {
	var hm = document.createElement("script");
	hm.src = "https://hm.baidu.com/hm.js?6d06f826e125297d4ce0fa7a1449328e";
	var s = document.getElementsByTagName("script")[0]; 
	s.parentNode.insertBefore(hm, s);
})();
</script>


<link rel="alternate" href="/atom.xml" title="丛烨-shimmerjordan" type="application/atom+xml">
</head>

</html>

	<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/font-awesome/css/font-awesome.min.css">
	<script src="https://cdn.jsdelivr.net/gh/stevenjoezhang/live2d-widget@latest/autoload.js"></script>


<body>
  <div id="app">
    
      
    <main class="content on">
      <section class="outer">
  <article
  id="post-DeployGithubActions"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h1 class="article-title sea-center" style="border-left:0" itemprop="name">
  Deploy Github Actions
</h1>
 

    </header>
     
    <div class="article-meta">
      <a href="/2021/02/01/DeployGithubActions/" class="article-date">
  <time datetime="2021-02-01T07:38:12.000Z" itemprop="datePublished">2021-02-01</time>
</a> 
  <div class="article-category">
    <a class="article-category-link" href="/categories/%E6%96%B0%E6%89%8B%E6%8C%87%E5%8C%97/">新手指北</a>
  </div>
  
<div class="word_count">
    <span class="post-time">
        <span class="post-meta-item-icon">
            <i class="ri-quill-pen-line"></i>
            <span class="post-meta-item-text"> 字数统计:</span>
            <span class="post-count">1.2k</span>
        </span>
    </span>

    <span class="post-time">
        &nbsp; | &nbsp;
        <span class="post-meta-item-icon">
            <i class="ri-book-open-line"></i>
            <span class="post-meta-item-text"> 阅读时长≈</span>
            <span class="post-count">7 分钟</span>
        </span>
    </span>
</div>
 
    </div>
      
    <div class="tocbot"></div>




  
    <div class="article-entry" itemprop="articleBody">
       
  <p>Sometimes automated deployment projects or timed tasks need to be deployed online, but these are for temporary use or these lightweight applications do not warrant the additional purchase of a cloud server for deployment. This is when you might consider using Github Actions for automated deployments.</p>
<p><a href="#1">GitHub Actions[1]</a> is GitHub’s <a href="#2">continuous integration service[2]</a>, launched in <a href="#3">October 2018[3]</a>. It is very powerful in that each action is used to perform an action, such as grabbing code, running tests, logging into a remote server, publishing to a third-party service, and so on. Combining these actions is a process of continuous integration. Of course, these actions are shared in the GitHub code repository, so we can refer to them directly.</p>
<p>Github Actions provides a complete server environment with the following server specifications</p>
<ul>
<li>2-core CPU</li>
<li>7 GB RAM memory</li>
<li>84 GB of SSD hard disk space</li>
</ul>
<p>Detailed system environment information is shown in the following figure:</p>
<center>
    <img style="border-radius: 0.3125em;
    box-shadow: 0 2px 4px 0 rgba(34,36,38,.12),0 2px 10px 0 rgba(34,36,38,.08);" 
    src="https://gcore.jsdelivr.net/gh/shimmerjordan/pic_bed@main/blog/2021/02/02/ym5WQJ.png" width="76%">
    <br>
    <div style="color:orange; border-bottom: 1px solid #d9d9d9;
    display: inline-block;
    color: #999;
    padding: 2px;">System environment information</div>
</center>

<p>Of course, you can use Windows Server 2019 and macOS X Catalina 10.15 in addition to Ubuntu.</p>
<span id="more"></span>
<p>This looks great, but GitHub Actions itself doesn’t allow direct connections for interactive operations, which means you can’t connect to the server via SSH. If there was a way to connect directly to the server interactively, wouldn’t that be like getting one or more VPS with an E5 2vCPU/7G RAM/90G SSD configuration for free?</p>
<p>This article will show you how you can get around the limitations of GitHub Actions itself and connect directly to the server by doing a few tricks!</p>
<blockquote>
<p>Note: Please do not use it for malicious purposes. All consequences such as banning, deterioration of Sino-American relations, atomic bombing, World War III, etc. are not the author’s responsibility.</p>
</blockquote>
<h1 id="Option-One"><a href="#Option-One" class="headerlink" title="Option One"></a>Option One</h1><ul>
<li><a href="#4">mxschmitt/action-tmate[4]</a></li>
</ul>
<p>This is the first action that implements <a href="#5">tmate[5]</a> to connect to the Actions server, but this solution cannot proceed to the next step after exiting the connection, so it has little value in practice and can only be used for SSH connections. However, due to its groundbreaking role, I decided to put it first.</p>
<p>Example workflow file:</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">name:</span> <span class="string">CI</span></span><br><span class="line"><span class="string">on:</span> [<span class="string">push</span>]</span><br><span class="line"><span class="attr">jobs:</span></span><br><span class="line">  <span class="attr">build:</span></span><br><span class="line">    <span class="string">runs-on:</span> <span class="string">ubuntu-latest</span></span><br><span class="line">    <span class="attr">steps:</span></span><br><span class="line">    <span class="string">-</span> <span class="string">uses:</span> <span class="string">actions/checkout@v2</span></span><br><span class="line">    <span class="string">-</span> <span class="string">name:</span> <span class="string">Setup</span> <span class="string">tmate</span> <span class="string">session</span></span><br><span class="line">      <span class="string">uses:</span> <span class="string">mxschmitt/action-tmate@v2</span></span><br></pre></td></tr></table></figure>
<h1 id="Option-Two"><a href="#Option-Two" class="headerlink" title="Option Two"></a>Option Two</h1><ul>
<li><a href="#6">csexton/debugger-action[6]</a></li>
</ul>
<p>This action is inspired by <a href="#7">mxschmitt/action-tmate[7]</a>, which also connects via tmate and allows you to continue to the next step after exiting the connection, making it better suited for use in real-world projects. The authors have added an automatic disconnect for 15 minutes by default, probably in the interest of saving resources for GitHub, but this can be removed by running <code>touch /tmp/keepalive</code>.</p>
<p>Example workflow file:</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">name:</span> <span class="string">debugger-action</span></span><br><span class="line"><span class="string">on:</span> </span><br><span class="line">  <span class="attr">watch:</span></span><br><span class="line">    <span class="string">types:</span> <span class="string">started</span></span><br><span class="line"><span class="attr">jobs:</span></span><br><span class="line">  <span class="attr">build:</span></span><br><span class="line">    <span class="string">runs-on:</span> <span class="string">ubuntu-latest</span></span><br><span class="line">    <span class="attr">steps:</span></span><br><span class="line">     <span class="string">-</span> <span class="string">uses:</span> <span class="string">actions/checkout@v2</span></span><br><span class="line"> </span><br><span class="line">     <span class="string">-</span> <span class="string">name:</span> <span class="string">Setup</span> <span class="string">Debug</span> <span class="string">Session</span></span><br><span class="line">       <span class="string">uses:</span> <span class="string">csexton/debugger-action@master</span></span><br></pre></td></tr></table></figure>
<p>Action Log output:</p>
<center>
    <img style="border-radius: 0.3125em;
    box-shadow: 0 2px 4px 0 rgba(34,36,38,.12),0 2px 10px 0 rgba(34,36,38,.08);" 
    src="https://gcore.jsdelivr.net/gh/shimmerjordan/pic_bed@main/blog/2021/02/01/yZi4BV.png" width="100%">
    <br>
    <div style="color:orange; border-bottom: 1px solid #d9d9d9;
    display: inline-block;
    color: #999;
    padding: 2px;">Action Log</div>
</center>

<p>Here you can use the connection given for SSH connections, but sometimes I have some problems running OpenSSH under windows. So I choose to use a browser to open <code>https://tmate.io/t/authToken</code> to connect to the remote host. The <code>authToken</code> here is shown in the token string after the ssh command. In the example given above, the link is <code>https://tmate.io/t/vX3de9KCggEWpQTcc8B9xYuaP</code></p>
<h1 id="Option-Three"><a href="#Option-Three" class="headerlink" title="Option Three"></a>Option Three</h1><p>Instead of using action to achieve this, the solution goes the other way and uses ngrok to penetrate the intranet directly, with the following script.</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="keyword">if</span> [[ -z <span class="string">&quot;<span class="variable">$NGROK_TOKEN</span>&quot;</span> ]]; <span class="keyword">then</span></span><br><span class="line">  <span class="built_in">echo</span> <span class="string">&quot;Please set &#x27;NGROK_TOKEN&#x27;&quot;</span></span><br><span class="line">  <span class="built_in">exit</span> 2</span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"> </span><br><span class="line"><span class="keyword">if</span> [[ -z <span class="string">&quot;<span class="variable">$USER_PASS</span>&quot;</span> ]]; <span class="keyword">then</span></span><br><span class="line">  <span class="built_in">echo</span> <span class="string">&quot;Please set &#x27;USER_PASS&#x27; for user: <span class="variable">$USER</span>&quot;</span></span><br><span class="line">  <span class="built_in">exit</span> 3</span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"> </span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;### Install ngrok ###&quot;</span></span><br><span class="line"> </span><br><span class="line">wget -q https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-386.zip</span><br><span class="line">unzip ngrok-stable-linux-386.zip</span><br><span class="line"><span class="built_in">chmod</span> +x ./ngrok</span><br><span class="line"> </span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;### Update user: <span class="variable">$USER</span> password ###&quot;</span></span><br><span class="line"><span class="built_in">echo</span> -e <span class="string">&quot;<span class="variable">$USER_PASS</span>\n<span class="variable">$USER_PASS</span>&quot;</span> | sudo passwd <span class="string">&quot;<span class="variable">$USER</span>&quot;</span></span><br><span class="line"> </span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;### Start ngrok proxy for 22 port ###&quot;</span></span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="built_in">rm</span> -f .ngrok.log</span><br><span class="line">./ngrok authtoken <span class="string">&quot;<span class="variable">$NGROK_TOKEN</span>&quot;</span></span><br><span class="line">./ngrok tcp 22 --<span class="built_in">log</span> <span class="string">&quot;.ngrok.log&quot;</span> &amp;</span><br><span class="line"> </span><br><span class="line"><span class="built_in">sleep</span> 10</span><br><span class="line">HAS_ERRORS=$(grep <span class="string">&quot;command failed&quot;</span> &lt; .ngrok.log)</span><br><span class="line"> </span><br><span class="line"><span class="keyword">if</span> [[ -z <span class="string">&quot;<span class="variable">$HAS_ERRORS</span>&quot;</span> ]]; <span class="keyword">then</span></span><br><span class="line">  <span class="built_in">echo</span> <span class="string">&quot;&quot;</span></span><br><span class="line">  <span class="built_in">echo</span> <span class="string">&quot;==========================================&quot;</span></span><br><span class="line">  <span class="built_in">echo</span> <span class="string">&quot;To connect: <span class="subst">$(grep -o -E <span class="string">&quot;tcp://(.+)&quot;</span> &lt; .ngrok.log | sed <span class="string">&quot;s/tcp:\/\//ssh <span class="variable">$USER</span>@/&quot;</span> | sed <span class="string">&quot;s/:/ -p /&quot;</span>)</span>&quot;</span></span><br><span class="line">  <span class="built_in">echo</span> <span class="string">&quot;==========================================&quot;</span></span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">  <span class="built_in">echo</span> <span class="string">&quot;<span class="variable">$HAS_ERRORS</span>&quot;</span></span><br><span class="line">  <span class="built_in">exit</span> 4</span><br><span class="line"><span class="keyword">fi</span></span><br></pre></td></tr></table></figure>
<p>This script is used to create a TCP tunnel for the SSH service and print out the commands to connect to the remote server over the public network.</p>
<p>First you need to register an account on <a href="#8">ngrok’s official website[8]</a> and generate a Tunnel Authtoken: <a target="_blank" rel="noopener" href="https://dashboard.ngrok.com/auth">https://dashboard.ngrok.com/auth</a>. Then create the following workflow.</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">name:</span> <span class="string">Debugging</span> <span class="string">with</span> <span class="string">SSH</span></span><br><span class="line"><span class="string">on:</span> <span class="string">push</span></span><br><span class="line"><span class="attr">jobs:</span></span><br><span class="line">  <span class="attr">build:</span></span><br><span class="line">    <span class="string">runs-on:</span> <span class="string">ubuntu-latest</span></span><br><span class="line">    <span class="attr">steps:</span></span><br><span class="line">     <span class="string">-</span> <span class="string">uses:</span> <span class="string">actions/checkout@v1</span></span><br><span class="line"> </span><br><span class="line">     <span class="string">-</span> <span class="string">name:</span> <span class="string">Try</span> <span class="string">Build</span></span><br><span class="line">       <span class="string">run:</span> <span class="string">./not-exist-file.sh</span> <span class="string">it</span> <span class="string">bloke</span> <span class="string">build</span></span><br><span class="line"> </span><br><span class="line">     <span class="string">-</span> <span class="string">name:</span> <span class="string">Start</span> <span class="string">SSH</span> <span class="string">via</span> <span class="string">Ngrok</span></span><br><span class="line">       <span class="string">if:</span> <span class="string">$&#123;&#123;</span> <span class="string">failure()</span> <span class="string">&#125;&#125;</span></span><br><span class="line">       <span class="string">run:</span> <span class="string">curl</span> <span class="string">-sL</span> <span class="string">https://gist.githubusercontent.com/retyui/7115bb6acf151351a143ec8f96a7c561/raw/7099b9db76729dc5761da72aa8525f632d8875c9/debug-github-actions.sh</span> <span class="string">|</span> <span class="string">bash</span></span><br><span class="line">       <span class="attr">env:</span></span><br><span class="line">        <span class="comment"># After sign up on the https://ngrok.com/</span></span><br><span class="line">        <span class="comment"># You can find this token here: https://dashboard.ngrok.com/get-started/setup</span></span><br><span class="line">        <span class="string">NGROK_TOKEN:</span> <span class="string">$&#123;&#123;</span> <span class="string">secrets.NGROK_TOKEN</span> <span class="string">&#125;&#125;</span></span><br><span class="line"> </span><br><span class="line">        <span class="comment"># This password you will use when authorizing via SSH </span></span><br><span class="line">        <span class="string">USER_PASS:</span> <span class="string">$&#123;&#123;</span> <span class="string">secrets.USER_PASS</span> <span class="string">&#125;&#125;</span></span><br><span class="line"> </span><br><span class="line">     <span class="string">-</span> <span class="string">name:</span> <span class="string">Don&#x27;t</span> <span class="string">kill</span> <span class="string">instace</span></span><br><span class="line">       <span class="string">if:</span> <span class="string">$&#123;&#123;</span> <span class="string">failure()</span> <span class="string">&#125;&#125;</span></span><br><span class="line">       <span class="string">run:</span> <span class="string">sleep</span> <span class="string">1h</span> <span class="comment"># Prevent to killing instance after failure</span></span><br></pre></td></tr></table></figure>
<p>The default server duration is 1 hour, but you can adjust this. The TOKEN and SSH passwords in this case are best done the way recommended in workflow, by creating the Secret in GitHub and then referencing the Secret in workflow. See the official documentation [9] for details.</p>
<h1 id="Additional-notes"><a href="#Additional-notes" class="headerlink" title="Additional notes"></a>Additional notes</h1><h2 id="Switching-to-a-root-user-on-linux"><a href="#Switching-to-a-root-user-on-linux" class="headerlink" title="Switching to a root user on linux"></a>Switching to a root user on linux</h2><p><strong>(1)<code>sudo</code> command</strong> </p>
<p><code>example@ubuntu:~$ sudo</code></p>
<p>This will give you superuser privileges by entering the current admin user password. However, by default root privileges are disabled after 5 minutes.</p>
<p><strong>(2) <code>sudo -i</code></strong></p>
<p><code>example@ubuntu:~$ sudo -i</code></p>
<p>In this way you can get to the root user by entering the password of the current admin user.</p>
<p><strong>(3) If you want to use root privileges all the time, you have to switch to the root user via <code>su</code>.</strong></p>
<p>Then we first have to reset the password for the root user:</p>
<p><code>example@ubuntu:~$ sudo -i</code></p>
<p><code>example@ubuntu:~$ sudo passwd root</code></p>
<p>This will set the password for the root user.</p>
<p><strong>(4) After that you can freely switch to the root user</strong></p>
<p><code>example@ubuntu:~$ su</code></p>
<p>Enter the password for the root user.</p>
<p><code>su &quot;king&quot;</code>or <code>exit</code> to return to user rights</p>
<h2 id="Example"><a href="#Example" class="headerlink" title="Example"></a>Example</h2><p>Here are some automated Github Actions I have deployed:</p>
<ul>
<li><a target="_blank" rel="noopener" href="https://github.com/shimmerjordan/health-check-automation">支持Github Action的NEU健康打卡自动化python脚本</a></li>
<li><a target="_blank" rel="noopener" href="https://github.com/shimmerjordan/hub-mirror">Mirror github repo to other platforms such as gitee via github actions</a></li>
<li><a target="_blank" rel="noopener" href="https://github.com/shimmerjordan/github-statis">github account statistics based on ‘github action’, using py script to generate svg statistics graphs</a></li>
<li><a target="_blank" rel="noopener" href="https://github.com/shimmerjordan/GLaDOS-autoCheckin">Automatic check-in to GLaDOS via timed tasks based on Github Actions</a></li>
<li><a target="_blank" rel="noopener" href="https://github.com/shimmerjordan/sz-education">This is a repository using github actions to run super-linter automatically</a></li>
</ul>
<h1 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h1><div id="1" ><a href="https://github.com/features/actions" target="_blank">[1]. GitHub Actions</a></div>

<div id="2" ><a href="http://www.ruanyifeng.com/blog/2015/09/continuous-integration.html" target="_blank">[2]. 持续集成服务</a></div>

<div id="3" ><a href="https://github.blog/changelog/2018-10-16-github-actions-limited-beta/" target="_blank">[3]. 推出</a></div>

<div id="4" ><a href="https://github.com/mxschmitt/action-tmate" target="_blank">[4]. mxschmitt/action-tmate</a></div>

<div id="5" ><a href="https://github.com/tmate-io/tmate" target="_blank">[5]. tmate</a></div>

<div id="6" ><a href="https://github.com/csexton/debugger-action" target="_blank">[6]. csexton/debugger-action</a></div>

<div id="7" ><a href="https://github.com/mxschmitt/action-tmate" target="_blank">[7]. mxschmitt/action-tmate</a></div>

<div id="8" ><a href="https://ngrok.com/" target="_blank">[8]. ngrok 的官网</a></div>

<div id="9" ><a href="https://docs.github.com/cn/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets" target="_blank">[9]. 官方文档</a></div>

<div id="9" ><a href="https://p3terx.com/archives/ssh-to-the-github-actions-virtual-server-environment.html" target="_blank">[10]. SSH 连接到 GitHub Actions 虚拟服务器环境</a></div> 
      <!-- reward -->
      
      <div id="reword-out">
        <div id="reward-btn">
          打赏
        </div>
      </div>
      
    </div>
    

    <!-- copyright -->
    
    <div class="declare">
      <ul class="post-copyright">
        <li>
          <i class="ri-copyright-line"></i>
          <strong>版权声明： </strong>
          
          本博客所有文章除特别声明外，著作权归作者所有。转载请注明出处！
          
        </li>
      </ul>
    </div>
    
    <footer class="article-footer">
       
<div class="share-btn">
      <span class="share-sns share-outer">
        <i class="ri-share-forward-line"></i>
        分享
      </span>
      <div class="share-wrap">
        <i class="arrow"></i>
        <div class="share-icons">
          
          <a class="weibo share-sns" href="javascript:;" data-type="weibo">
            <i class="ri-weibo-fill"></i>
          </a>
          <a class="weixin share-sns wxFab" href="javascript:;" data-type="weixin">
            <i class="ri-wechat-fill"></i>
          </a>
          <a class="qq share-sns" href="javascript:;" data-type="qq">
            <i class="ri-qq-fill"></i>
          </a>
          <a class="douban share-sns" href="javascript:;" data-type="douban">
            <i class="ri-douban-line"></i>
          </a>
          <!-- <a class="qzone share-sns" href="javascript:;" data-type="qzone">
            <i class="icon icon-qzone"></i>
          </a> -->
          
          <a class="facebook share-sns" href="javascript:;" data-type="facebook">
            <i class="ri-facebook-circle-fill"></i>
          </a>
          <a class="twitter share-sns" href="javascript:;" data-type="twitter">
            <i class="ri-twitter-fill"></i>
          </a>
          <a class="google share-sns" href="javascript:;" data-type="google">
            <i class="ri-google-fill"></i>
          </a>
        </div>
      </div>
</div>

<div class="wx-share-modal">
    <a class="modal-close" href="javascript:;"><i class="ri-close-circle-line"></i></a>
    <p>扫一扫，分享到微信</p>
    <div class="wx-qrcode">
      <img src="//api.qrserver.com/v1/create-qr-code/?size=150x150&data=https://blog.shimmerjordan.eu.org/2021/02/01/DeployGithubActions/" alt="微信分享二维码">
    </div>
</div>

<div id="share-mask"></div>  
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Cloud-Server/" rel="tag">Cloud Server</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/git/" rel="tag">git</a></li></ul>

    </footer>
  </div>

   
  <nav class="article-nav">
    
      <a href="/2021/02/06/Hexo-seo/" class="article-nav-link">
        <strong class="article-nav-caption">上一篇</strong>
        <div class="article-nav-title">
          
            Hexo-seo Optimization Tips
          
        </div>
      </a>
    
    
      <a href="/2021/02/01/hexo_on_cloud_server/" class="article-nav-link">
        <strong class="article-nav-caption">下一篇</strong>
        <div class="article-nav-title">Hexo的云服务器部署</div>
      </a>
    
  </nav>

   
<!-- valine评论 -->
<div id="vcomments-box">
  <div id="vcomments"></div>
</div>
<script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/valine@1.4.14/dist/Valine.min.js"></script>
<script>
  new Valine({
    el: "#vcomments",
    app_id: "StYfTMDp78X0EltFR16ve2q5-gzGzoHsz",
    app_key: "G4RPxRpXG6RwdfpnJefOSnyy",
    path: window.location.pathname,
    avatar: "wavatar",
    placeholder: "ヾﾉ≧∀≦)o来啊，快活啊!",
    recordIP: true,
  });
  const infoEle = document.querySelector("#vcomments .info");
  if (infoEle && infoEle.childNodes && infoEle.childNodes.length > 0) {
    infoEle.childNodes.forEach(function (item) {
      item.parentNode.removeChild(item);
    });
  }
</script>
<style>
  #vcomments-box {
    padding: 5px 30px;
  }

  @media screen and (max-width: 800px) {
    #vcomments-box {
      padding: 5px 0px;
    }
  }

  #vcomments-box #vcomments {
    background-color: #fff;
  }

  .v .vlist .vcard .vh {
    padding-right: 20px;
  }

  .v .vlist .vcard {
    padding-left: 10px;
  }
</style>

 
   
   
<!-- minivaline评论 -->
<div id="mvcomments-box">
  <div id="mvcomments"></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/minivaline@latest"></script>
<script>
    new MiniValine(Object.assign({"enable":true,"mode":"DesertsP","placeholder":"Write a Comment","math":true,"md":true,"enableQQ":true,"NoRecordIP":false,"visitor":true,"maxNest":6,"pageSize":6,"adminEmailMd5":"de8a7aa53d07e6b6bceb45c64027763d","tagMeta":["管理员","小伙伴","访客"],"master":["de8a7aa53d07e6b6bceb45c64027763d"],"friends":["b5bd5d836c7a0091aa8473e79ed4c25e","adb7d1cd192658a55c0ad22a3309cecf","3ce1e6c77b4910f1871106cb30dc62b0","cfce8dc43725cc14ffcd9fb4892d5bfc"],"lang":null,"emoticonUrl":["https://cdn.jsdelivr.net/npm/alus@latest","https://cdn.jsdelivr.net/gh/MiniValine/qq@latest","https://cdn.jsdelivr.net/gh/MiniValine/Bilibilis@latest","https://cdn.jsdelivr.net/gh/MiniValine/tieba@latest","https://cdn.jsdelivr.net/gh/MiniValine/twemoji@latest","https://cdn.jsdelivr.net/gh/MiniValine/weibo@latest"]}, {
	  el: '#mvcomments',
    }));
  const infoEle = document.querySelector('#mvcomments .info');
  if (infoEle && infoEle.childNodes && infoEle.childNodes.length > 0) {
      infoEle.childNodes.forEach(function (item) {
          item.parentNode.removeChild(item);
      });
  }
</script>
<style>
	#mvcomments-box {
		padding: 5px 30px;
	}
	@media screen and (max-width: 800px) {
		#mvcomments-box {
		  padding: 5px 0px;
		}
	}
	.darkmode .MiniValine *{
		color: #f1f1f1!important;
	}
	.darkmode .commentTrigger{
		background-color: #403e3e !important;
	  }
	.darkmode .MiniValine .vpage .more{
		background: #21232F
	}
	.darkmode img{
		filter: brightness(30%)
	}
	.darkmode .MiniValine .vlist .vcard .vcomment-body .text-wrapper .vcomment.expand:before{
		background: linear-gradient(180deg, rgba(246,246,246,0), rgba(0,0,0,0.9))
	}
	.darkmode .MiniValine .vlist .vcard .vcomment-body .text-wrapper .vcomment.expand:after{
		background: rgba(0,0,0,0.9)
	}
	.darkmode .MiniValine .vlist .vcard .vcomment-body .text-wrapper .vcomment pre{
		background: #282c34
		border: 1px solid #282c34
	}
	.darkmode .MiniValine .vinputs-area .textarea-wrapper textarea{
		color: #000;
	}
	.darkmode .MiniValine .vinputs-area .auth-section .input-wrapper input{
		color: #000;
	}
	.darkmode .MiniValine .vinputs-area .vextra-area .vsmile-icons{
		background: transparent;
	}
	.darkmode .MiniValine .vinputs-wrap{
		border-color: #b2b2b5;
	}
	.darkmode .MiniValine .vinputs-wrap:hover{
		border: 1px dashed #2196f3;
	}
	.darkmode .MiniValine .vinputs-area .auth-section .input-wrapper{
		border-bottom: 1px dashed #b2b2b5;
	}
	.darkmode .MiniValine .vinputs-area .auth-section .input-wrapper:hover{
		border-bottom: 1px dashed #2196f3;
	}
	.darkmode .MiniValine .vbtn{
		background-color: transparent!important;
	}
	.darkmode .MiniValine .vbtn:hover{
		border: 1px dashed #2196f3;
	}
</style>

    
</article>

</section>
      <footer class="footer">
  <div class="outer">
    <ul>
      <li>
        Copyrights &copy;
        2019-2024
        <i class="ri-heart-fill heart_icon"></i> 鞠桥丹-QIAODAN JU
      </li>
    </ul>
    <ul>
      <li>
        
        
        
        由 <a href="https://hexo.io" target="_blank">Hexo</a> 强力驱动
        <span class="division">|</span>
        主题 - <a href="https://github.com/Shen-Yu/hexo-theme-ayer" target="_blank">Ayer</a>
        
      </li>
    </ul>
    <ul>
      <li>
        
        
        <span>
  <span><i class="ri-user-3-fill"></i>访问人数:<span id="busuanzi_value_site_uv"></span></s>
  <span class="division">|</span>
  <span><i class="ri-eye-fill"></i>浏览次数:<span id="busuanzi_value_page_pv"></span></span>
</span>
        
      </li>
    </ul>
    <ul>
      
    </ul>
    <ul>
      
    </ul>
    <ul>
      <li>
        <!-- cnzz统计 -->
        
        <script type="text/javascript" src='https://s4.cnzz.com/z_stat.php?id=1279035150&amp;web_id=1279035150'></script>
        
      </li>
    </ul>
  </div>
</footer>
      <div class="float_btns">
        <div class="totop" id="totop">
  <i class="ri-arrow-up-line"></i>
</div>

<div class="todark" id="todark">
  <i class="ri-moon-line"></i>
</div>

      </div>
    </main>
    <aside class="sidebar on">
      <button class="navbar-toggle"></button>
<nav class="navbar">
  
  <div class="logo">
    <a href="/"><img src="/images/ayer-side.svg" alt="丛烨-shimmerjordan"></a>
  </div>
  
  <ul class="nav nav-main">
    
    <li class="nav-item">
      <a class="nav-item-link" href="/">Home</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/archives">Catalogue</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/tags">Tags</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/tags/%E9%9A%8F%E7%AC%94/">Essay</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/categories">Archives</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/friends">Friends</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/2020/01/18/about">About</a>
    </li>
    
  </ul>
</nav>
<nav class="navbar navbar-bottom">
  <ul class="nav">
    <li class="nav-item">
      
      <a class="nav-item-link nav-item-search"  title="搜索">
        <i class="ri-search-line"></i>
      </a>
      
      
      <a class="nav-item-link" target="_blank" href="/atom.xml" title="RSS Feed">
        <i class="ri-rss-line"></i>
      </a>
      
    </li>
  </ul>
</nav>
<div class="search-form-wrap">
  <div class="local-search local-search-plugin">
  <input type="search" id="local-search-input" class="local-search-input" placeholder="Search...">
  <div id="local-search-result" class="local-search-result"></div>
</div>
</div>
    </aside>
    <script>
      if (window.matchMedia("(max-width: 768px)").matches) {
        document.querySelector('.content').classList.remove('on');
        document.querySelector('.sidebar').classList.remove('on');
      }
    </script>
    <div id="mask"></div>

<!-- #reward -->
<div id="reward">
  <span class="close"><i class="ri-close-line"></i></span>
  <p class="reward-p"><i class="ri-cup-line"></i>请我喝杯蓝莓汁吧~</p>
  <div class="reward-box">
    
    <div class="reward-item">
      <img class="reward-img" src="/images/alipay.jpg">
      <span class="reward-type">支付宝</span>
    </div>
    
    
    <div class="reward-item">
      <img class="reward-img" src="/images/wechat.jpg">
      <span class="reward-type">微信</span>
    </div>
    
  </div>
</div>
    
<script src="/js/jquery-2.0.3.min.js"></script>


<script src="/js/lazyload.min.js"></script>

<!-- Tocbot -->


<script src="/js/tocbot.min.js"></script>

<script>
  tocbot.init({
    tocSelector: '.tocbot',
    contentSelector: '.article-entry',
    headingSelector: 'h1, h2, h3, h4, h5, h6',
    hasInnerContainers: true,
    scrollSmooth: true,
    scrollContainer: 'main',
    positionFixedSelector: '.tocbot',
    positionFixedClass: 'is-position-fixed',
    fixedSidebarOffset: 'auto'
  });
</script>

<script src="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.css">
<script src="https://cdn.jsdelivr.net/npm/justifiedGallery@3.7.0/dist/js/jquery.justifiedGallery.min.js"></script>

<script src="/dist/main.js"></script>

<!-- ImageViewer -->

<!-- Root element of PhotoSwipe. Must have class pswp. -->
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">

    <!-- Background of PhotoSwipe. 
         It's a separate element as animating opacity is faster than rgba(). -->
    <div class="pswp__bg"></div>

    <!-- Slides wrapper with overflow:hidden. -->
    <div class="pswp__scroll-wrap">

        <!-- Container that holds slides. 
            PhotoSwipe keeps only 3 of them in the DOM to save memory.
            Don't modify these 3 pswp__item elements, data is added later on. -->
        <div class="pswp__container">
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
        </div>

        <!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
        <div class="pswp__ui pswp__ui--hidden">

            <div class="pswp__top-bar">

                <!--  Controls are self-explanatory. Order can be changed. -->

                <div class="pswp__counter"></div>

                <button class="pswp__button pswp__button--close" title="Close (Esc)"></button>

                <button class="pswp__button pswp__button--share" style="display:none" title="Share"></button>

                <button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>

                <button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>

                <!-- Preloader demo http://codepen.io/dimsemenov/pen/yyBWoR -->
                <!-- element will get class pswp__preloader--active when preloader is running -->
                <div class="pswp__preloader">
                    <div class="pswp__preloader__icn">
                        <div class="pswp__preloader__cut">
                            <div class="pswp__preloader__donut"></div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
                <div class="pswp__share-tooltip"></div>
            </div>

            <button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
            </button>

            <button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
            </button>

            <div class="pswp__caption">
                <div class="pswp__caption__center"></div>
            </div>

        </div>

    </div>

</div>

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/default-skin/default-skin.min.css">
<script src="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe-ui-default.min.js"></script>

<script>
    function viewer_init() {
        let pswpElement = document.querySelectorAll('.pswp')[0];
        let $imgArr = document.querySelectorAll(('.article-entry img:not(.reward-img)'))

        $imgArr.forEach(($em, i) => {
            $em.onclick = () => {
                // slider展开状态
                // todo: 这样不好，后面改成状态
                if (document.querySelector('.left-col.show')) return
                let items = []
                $imgArr.forEach(($em2, i2) => {
                    let img = $em2.getAttribute('data-idx', i2)
                    let src = $em2.getAttribute('data-target') || $em2.getAttribute('src')
                    let title = $em2.getAttribute('alt')
                    // 获得原图尺寸
                    const image = new Image()
                    image.src = src
                    items.push({
                        src: src,
                        w: image.width || $em2.width,
                        h: image.height || $em2.height,
                        title: title
                    })
                })
                var gallery = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, items, {
                    index: parseInt(i)
                });
                gallery.init()
            }
        })
    }
    viewer_init()
</script>

<!-- MathJax -->

<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
      tex2jax: {
          inlineMath: [ ['$','$'], ["\\(","\\)"]  ],
          processEscapes: true,
          skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
      }
  });

  MathJax.Hub.Queue(function() {
      var all = MathJax.Hub.getAllJax(), i;
      for(i=0; i < all.length; i += 1) {
          all[i].SourceElement().parentNode.className += ' has-jax';
      }
  });
</script>

<script src="https://cdn.jsdelivr.net/npm/mathjax@2.7.6/unpacked/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<script>
  var ayerConfig = {
    mathjax: true
  }
</script>

<!-- Katex -->

<!-- busuanzi  -->


<script src="/js/busuanzi-2.3.pure.min.js"></script>


<!-- ClickLove -->


<script src="/js/clickLove.js"></script>


<!-- ClickBoom1 -->

<!-- ClickBoom2 -->

<!-- CodeCopy -->


<link rel="stylesheet" href="/css/clipboard.css">

<script src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js"></script>
<script>
  function wait(callback, seconds) {
    var timelag = null;
    timelag = window.setTimeout(callback, seconds);
  }
  !function (e, t, a) {
    var initCopyCode = function(){
      var copyHtml = '';
      copyHtml += '<button class="btn-copy" data-clipboard-snippet="">';
      copyHtml += '<i class="ri-file-copy-2-line"></i><span>COPY</span>';
      copyHtml += '</button>';
      $(".highlight .code pre").before(copyHtml);
      $(".article pre code").before(copyHtml);
      var clipboard = new ClipboardJS('.btn-copy', {
        target: function(trigger) {
          return trigger.nextElementSibling;
        }
      });
      clipboard.on('success', function(e) {
        let $btn = $(e.trigger);
        $btn.addClass('copied');
        let $icon = $($btn.find('i'));
        $icon.removeClass('ri-file-copy-2-line');
        $icon.addClass('ri-checkbox-circle-line');
        let $span = $($btn.find('span'));
        $span[0].innerText = 'COPIED';
        
        wait(function () { // 等待两秒钟后恢复
          $icon.removeClass('ri-checkbox-circle-line');
          $icon.addClass('ri-file-copy-2-line');
          $span[0].innerText = 'COPY';
        }, 2000);
      });
      clipboard.on('error', function(e) {
        e.clearSelection();
        let $btn = $(e.trigger);
        $btn.addClass('copy-failed');
        let $icon = $($btn.find('i'));
        $icon.removeClass('ri-file-copy-2-line');
        $icon.addClass('ri-time-line');
        let $span = $($btn.find('span'));
        $span[0].innerText = 'COPY FAILED';
        
        wait(function () { // 等待两秒钟后恢复
          $icon.removeClass('ri-time-line');
          $icon.addClass('ri-file-copy-2-line');
          $span[0].innerText = 'COPY';
        }, 2000);
      });
    }
    initCopyCode();
  }(window, document);
</script>


<!-- CanvasBackground -->


<script src="/js/dz.js"></script>



    
  </div>
</body>

</html>